package com.example.demo.tools;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.Locale;

/**
 * 日期时间工具类
 * 基于 {@link Calendar}
 * 提供常用静态方法。连续操作时推荐实例化。
 */
public class EasyTime {

    // 默认日期格式
    private static final String FORMAT_DATE = "yyyy-MM-dd";
    // 默认时间格式
    private static final String FORMAT_TIME = "HH:mm:ss";
    // 默认日期时间格式
    private static final String FORMAT_DATE_TIME = "yyyy-MM-dd HH:mm:ss";

    // 默认日期时间格式的格式化工具
    private static final SimpleDateFormat SDF_DATE_TIME = new SimpleDateFormat(FORMAT_DATE_TIME);
    // 默认日期格式的格式化工具
    private static final SimpleDateFormat SDF_DATE = new SimpleDateFormat(FORMAT_DATE);
    // 默认时间格式的格式化工具
    private static final SimpleDateFormat SDF_TIME = new SimpleDateFormat(FORMAT_TIME);

    // 平年12个月各月天数，用以计算标准天
    private static final int[] COMMON_MONTH_DAY = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

    // 基础实例
    private Calendar instance;

    /**
     * 私有实例化
     *
     * @param instance
     */
    private EasyTime(Calendar instance) {
        this.instance = instance;
    }

    /**
     * 入口方法，静态
     * 入参日期对象{@link Date}, 日期字符串{@link String}, 毫秒数{@code long}(from 1970/01/01 00:00:00.000 GMT)
     * 特别强调支持{@link Timestamp}，因为其继承了{@link Date}
     */

    /**
     * 初始化
     * 使用当前系统时间
     *
     * @return
     */
    public static EasyTime init() {
        return new EasyTime(Calendar.getInstance());
    }

    /**
     * 初始化
     * 使用日期对象{@link Date}
     *
     * @param date 日期对象
     * @return
     */
    public static EasyTime init(@NotNull Date date) {
        Calendar instance = new Calendar.Builder().setInstant(date).build();
        return new EasyTime(instance);
    }

    /**
     * 初始化
     * 使用日期对象{@link Date}并设置区域{@link Locale}
     *
     * @param date   日期对象
     * @param locale 区域
     * @return
     */
    public static EasyTime init(@NotNull Date date, @NotNull Locale locale) {
        Calendar instance = new Calendar.Builder().setInstant(date).build();
        return new EasyTime(instance);
    }

    /**
     * 初始化
     * 使用默认格式{@link #FORMAT_DATE_TIME}初始化
     *
     * @param dateTimeStr 日期时间字符串
     * @return
     * @throws ParseException
     */
    public static EasyTime init(@NotBlank String dateTimeStr) throws ParseException {
        return init(SDF_DATE_TIME.parse(dateTimeStr));
    }

    /**
     * 初始化
     * 使用默认格式{@link #FORMAT_DATE_TIME}，并设置区域{@link Locale}
     *
     * @param dateTimeStr 日期时间字符串
     * @param locale      区域
     * @return
     * @throws ParseException
     */
    public static EasyTime init(@NotBlank String dateTimeStr, @NotNull Locale locale) throws ParseException {
        return init(SDF_DATE_TIME.parse(dateTimeStr), locale);
    }

    /**
     * 初始化
     * 使用指定格式（允许时区）
     *
     * @param dateTimeStr 日期时间字符串
     * @param formatStr   日期时间格式
     * @return
     * @throws ParseException
     */
    public static EasyTime init(@NotBlank String dateTimeStr, @NotBlank String formatStr) throws ParseException {
        Date date = new SimpleDateFormat(formatStr).parse(dateTimeStr);
        return init(date);
    }

    /**
     * 初始化
     * 使用指定格式（允许时区），并设置区域{@link Locale}
     *
     * @param dateTimeStr 日期时间字符串
     * @param formatStr   日期时间格式
     * @param locale      区域
     * @return
     * @throws ParseException
     */
    public static EasyTime init(@NotBlank String dateTimeStr, @NotBlank String formatStr, @NotNull Locale locale) throws ParseException {
        Date date = new SimpleDateFormat(formatStr).parse(dateTimeStr);
        return init(date, locale);
    }

    /**
     * 初始化
     * 使用毫秒数
     *
     * @param milliseconds 毫秒数（from 1970/01/01 00:00:00.000 GMT）
     * @return
     */
    public static EasyTime init(long milliseconds) {
        Calendar instance = new Calendar.Builder().setInstant(milliseconds).build();
        return new EasyTime(instance);
    }

    /**
     * 初始化
     * 使用毫秒数，并设置区域{@link Locale}
     *
     * @param milliseconds 毫秒数（from 1970/01/01 00:00:00.000 GMT）
     * @param locale       区域
     * @return
     */
    public static EasyTime init(long milliseconds, @NotNull Locale locale) {
        Calendar instance = new Calendar.Builder().setInstant(milliseconds).setLocale(locale).build();
        return new EasyTime(instance);
    }


    /**
     * 输出
     * 对外输出日历对象{@link Calendar}, 时间戳{@link Timestamp}, 日期对象{@link Date}, 日期字符串{@link String}, 
     * 毫秒数{@code long}(from 1970/01/01 00:00:00.000 GMT)
     */

    /**
     * 输出日历对象{@link Calendar}
     * 一般情况下不推荐使用
     * @return
     */
    public Calendar toCalendar() {
        return new Calendar.Builder().setInstant(instance.getTimeInMillis()).build();
    }

    /**
     * 输出时间戳{@link Timestamp}
     *
     * @return
     */
    public Timestamp toStamp() {
        return Timestamp.from(instance.toInstant());
    }

    /**
     * 输出日期对象{@link Date}
     *
     * @return
     */
    public Date toDate() {
        return instance.getTime();
    }

    /**
     * 输出毫秒数{@code long}(from 1970/01/01 00:00:00.000 GMT)
     *
     * @return
     */
    public long toMillis() {
        return instance.getTimeInMillis();
    }

    /**
     * 日期时间设置
     * 设置年/月/日/时/分/秒/毫秒
     */

    /**
     * 设置指定字段的值
     *
     * @param field 字段
     * @param value 值
     * @return
     * @see Calendar#set(int, int)
     */
    public EasyTime set(int field, int value) {
        instance.set(field, value);
        return this;
    }

    /**
     * 设置年份
     *
     * @param year 年份
     * @return
     */
    public EasyTime setYear(int year) {
        instance.set(Calendar.YEAR, year);
        return this;
    }

    /**
     * 设置月份（注意月份范围0~11）
     *
     * @param month 月份
     * @return
     * @see Calendar#MONTH
     */
    public EasyTime setMonth(int month) {
        instance.set(Calendar.MONTH, month);
        return this;
    }

    /**
     * 设置天(建议根据实际设置)
     *
     * @param day 天
     * @return
     */
    public EasyTime setDay(int day) {
        instance.set(Calendar.DAY_OF_MONTH, day);
        return this;
    }

    /**
     * 设置小时
     *
     * @param hour 时
     * @return
     */
    public EasyTime setHour(int hour) {
        instance.set(Calendar.HOUR_OF_DAY, hour);
        return this;
    }

    /**
     * 设置分钟
     *
     * @param minute 分
     * @return
     */
    public EasyTime setMinute(int minute) {
        instance.set(Calendar.MINUTE, minute);
        return this;
    }

    /**
     * 设置秒
     *
     * @param second 秒
     * @return
     */
    public EasyTime setSecond(int second) {
        instance.set(Calendar.SECOND, second);
        return this;
    }

    /**
     * 设置毫秒
     *
     * @param millis 毫秒
     * @return
     */
    public EasyTime setMillis(int millis) {
        instance.set(Calendar.MILLISECOND, millis);
        return this;
    }

    /**
     * 设置日期(年月日)
     *
     * @param year  年份
     * @param month 月份
     * @param day   日
     * @return
     */
    public EasyTime setDate(int year, int month, int day) {
        instance.set(year, month, day);
        return this;
    }

    /**
     * 设置时间（时分秒）
     *
     * @param hour   时
     * @param minute 分
     * @param second 秒
     * @return
     */
    public EasyTime setTime(int hour, int minute, int second) {
        setTime(instance, hour, minute, second);
        return this;
    }

    private static void setTime(Calendar calendar, int hour, int minute, int second) {
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
    }

    /**
     * 增减日期时间
     * 增减年/月/日/时/分/秒/毫秒
     */

    /**
     * 增减年份
     *
     * @param year 年
     * @return
     */
    public EasyTime addYear(int year) {
        instance.add(Calendar.YEAR, year);
        return this;
    }

    /**
     * 增减月份
     *
     * @param month 月
     * @return
     */
    public EasyTime addMonth(int month) {
        instance.add(Calendar.MONTH, month);
        return this;
    }

    /**
     * 增减天数
     *
     * @param day 天
     * @return
     */
    public EasyTime addDay(int day) {
        instance.add(Calendar.DAY_OF_MONTH, day);
        return this;
    }

    /**
     * 增减小时
     *
     * @param hour 小时
     * @return
     */
    public EasyTime addHour(int hour) {
        instance.add(Calendar.HOUR_OF_DAY, hour);
        return this;
    }

    /**
     * 增减分钟
     *
     * @param minute 分钟
     * @return
     */
    public EasyTime addMinute(int minute) {
        instance.add(Calendar.MINUTE, minute);
        return this;
    }

    /**
     * 增减秒
     *
     * @param second 秒
     * @return
     */
    public EasyTime addSecond(int second) {
        instance.add(Calendar.SECOND, second);
        return this;
    }

    /**
     * 增减毫秒
     *
     * @param millis 毫秒
     * @return
     */
    public EasyTime addMillis(int millis) {
        instance.add(Calendar.MILLISECOND, millis);
        return this;
    }

    /**
     * 计算开始和结束
     * 年头/年尾、月初/月末、日始/日终，均精确到毫秒
     */

    /**
     * 获取当前年份的初始时间
     *
     * @return
     */
    public EasyTime yearStart() {
        instance.set(Calendar.MONTH, 1);
        return monthStart();
    }

    /**
     * 获取指定日期当年的初始时间
     *
     * @param date 日期
     * @return
     */
    public static Date yearStart(@NotNull Date date) {
        Calendar calendar = new Calendar.Builder().setInstant(date).build();
        calendar.set(Calendar.MONTH, Calendar.JANUARY);
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        dayStart(calendar);
        return calendar.getTime();
    }

    /**
     * 获取指定日期当年的初始时间
     * 使用默认日期时间格式{@link #FORMAT_DATE_TIME}解析及输出
     *
     * @param dateTimeStr 日期字符串
     * @return
     * @throws ParseException
     */
    public static String yearStart(@NotBlank String dateTimeStr) throws ParseException {
        return SDF_DATE_TIME.format(yearStart(SDF_DATE_TIME.parse(dateTimeStr)));
    }

    /**
     * 获取指定日期当年的初始时间
     * 使用指定的日期格式解析及输出
     *
     * @param dateTimeStr 日期字符串
     * @param pattern     日期格式
     * @return
     * @throws ParseException
     */
    public static String yearStart(@NotBlank String dateTimeStr, @NotBlank String pattern) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        return format.format(yearStart(format.parse(dateTimeStr)));
    }

    /**
     * 获取今年初始时间并按默认日期时间格式{@link #FORMAT_DATE_TIME}输出
     *
     * @return
     */
    public static String curYearStart() {
        return SDF_DATE_TIME.format(yearStart(new Date()));
    }

    /**
     * 获取今年初始时间并按指定格式输出
     *
     * @param pattern 日期格式
     * @return
     */
    public static String curYearStart(@NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(yearStart(new Date()));
    }

    /**
     * 获取当前年份的终末时间
     *
     * @return
     */
    public EasyTime yearEnd() {
        instance.set(Calendar.MONTH, Calendar.DECEMBER);
        instance.set(Calendar.DAY_OF_MONTH, 31);
        return dayEnd();
    }

    /**
     * 获取指定日期的当年终末时间
     *
     * @param date 日期
     * @return
     */
    public static Date yearEnd(@NotNull Date date) {
        Calendar calendar = new Calendar.Builder().setInstant(date).build();
        calendar.set(Calendar.MONTH, Calendar.DECEMBER);
        calendar.set(Calendar.DAY_OF_MONTH, 31);
        dayEnd(calendar);
        return calendar.getTime();
    }

    /**
     * 获取指定日期的当年终末时间
     * 使用默认日期时间格式{@link #FORMAT_DATE_TIME}解析及输出
     *
     * @param dateTimeStr 日期字符串
     * @return
     * @throws ParseException
     */
    public static String yearEnd(@NotBlank String dateTimeStr) throws ParseException {
        return SDF_DATE_TIME.format(yearEnd(SDF_DATE_TIME.parse(dateTimeStr)));
    }

    /**
     * 获取指定日期的当年终末时间
     * 使用指定的日期格式解析及输出
     *
     * @param dateTimeStr 日期字符串
     * @param pattern     日期格式
     * @return
     * @throws ParseException
     */
    public static String yearEnd(@NotBlank String dateTimeStr, @NotBlank String pattern) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        return format.format(yearEnd(format.parse(dateTimeStr)));
    }

    /**
     * 获取今年终末时间并按默认日期时间格式{@link #FORMAT_DATE_TIME}输出
     *
     * @return
     */
    public static String curYearEnd() {
        return SDF_DATE_TIME.format(yearEnd(new Date()));
    }

    /**
     * 获取今年终末时间并按指定格式输出
     *
     * @param pattern 日期格式
     * @return
     */
    public static String curYearEnd(@NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(yearEnd(new Date()));
    }

    /**
     * 获取当前月份初始时间
     *
     * @return
     */
    public EasyTime monthStart() {
        instance.set(Calendar.DAY_OF_MONTH, 1);
        return dayStart();
    }

    /**
     * 获取指定日期的当月初始时间
     *
     * @param date 日期
     * @return
     */
    public static Date monthStart(@NotNull Date date) {
        Calendar calendar = new Calendar.Builder().setInstant(date).build();
        calendar.set(Calendar.DAY_OF_MONTH, 1);
        dayStart(calendar);
        return calendar.getTime();
    }

    /**
     * 获取指定日期的当月初始时间
     * 使用默认日期时间格式{@link #FORMAT_DATE_TIME}解析及输出
     *
     * @param dateTimeStr 日期字符串
     * @return
     * @throws ParseException
     */
    public static String monthStart(@NotBlank String dateTimeStr) throws ParseException {
        return SDF_DATE_TIME.format(monthStart(SDF_DATE_TIME.parse(dateTimeStr)));
    }

    /**
     * 获取指定日期的当月初始时间
     * 使用指定的日期格式解析及输出
     *
     * @param dateTimeStr 日期字符串
     * @param pattern     日期格式
     * @return
     * @throws ParseException
     */
    public static String monthStart(@NotBlank String dateTimeStr, @NotBlank String pattern) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        return format.format(monthStart(format.parse(dateTimeStr)));
    }

    /**
     * 获取本月初始时间并按默认日期时间格式{@link #FORMAT_DATE_TIME}输出
     *
     * @return
     */
    public static String curMonthStart() {
        return SDF_DATE_TIME.format(monthStart(new Date()));
    }

    /**
     * 获取本月初始时间并按指定格式输出
     *
     * @param pattern 日期格式
     * @return
     */
    public static String curMonthStart(@NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(monthStart(new Date()));
    }

    /**
     * 获取当前月份终末时间
     *
     * @return
     */
    public EasyTime monthEnd() {
        instance.set(Calendar.DAY_OF_MONTH, instance.getActualMaximum(Calendar.DAY_OF_MONTH));
        return dayEnd();
    }

    /**
     * 获取指定日期的当月终末时间
     *
     * @param date 日期
     * @return
     */
    public static Date monthEnd(@NotNull Date date) {
        Calendar calendar = new Calendar.Builder().setInstant(date).build();
        calendar.set(Calendar.DAY_OF_MONTH, calendar.getActualMaximum(Calendar.DAY_OF_MONTH));
        dayEnd(calendar);
        return calendar.getTime();
    }

    /**
     * 获取指定日期的当月终末时间
     * 使用默认格式{@link #FORMAT_DATE_TIME}解析及输出日期字符串
     *
     * @param dateTimeStr 日期字符串
     * @return
     * @throws ParseException
     */
    public static String monthEnd(@NotBlank String dateTimeStr) throws ParseException {
        return SDF_DATE_TIME.format(monthEnd(SDF_DATE_TIME.parse(dateTimeStr)));
    }

    /**
     * 获取指定日期的当月终末时间
     * 使用指定格式解析及输出日期字符串
     *
     * @param dateTimeStr 日期字符串
     * @param pattern     日期格式
     * @return
     * @throws ParseException
     */
    public static String monthEnd(@NotBlank String dateTimeStr, @NotBlank String pattern) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        return format.format(monthEnd(format.parse(dateTimeStr)));
    }

    /**
     * 获取本月终末时间并按默认日期时间格式{@link #FORMAT_DATE_TIME}输出
     *
     * @return
     */
    public static String curMonthEnd() {
        return SDF_DATE_TIME.format(monthEnd(new Date()));
    }

    /**
     * 获取本月终末时间并按指定格式输出
     *
     * @param pattern 日期格式
     * @return
     */
    public static String curMonthEnd(@NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(monthEnd(new Date()));
    }

    /**
     * 获取当日开始时间
     *
     * @return
     */
    public EasyTime dayStart() {
        dayStart(instance);
        return this;
    }

    /**
     * 获取当日开始时间
     *
     * @param date 日期
     * @return
     */
    public static Date dayStart(@NotNull Date date) {
        Calendar calendar = new Calendar.Builder().setInstant(date).build();
        dayStart(calendar);
        return calendar.getTime();
    }

    /**
     * 获取当日开始时间
     * 使用默认格式{@link #FORMAT_DATE_TIME}解析及输出日期字符串
     *
     * @param dateTimeStr 日期字符串
     * @return
     * @throws ParseException
     */
    public static String dayStart(@NotBlank String dateTimeStr) throws ParseException {
        return SDF_DATE_TIME.format(dayStart(SDF_DATE_TIME.parse(dateTimeStr)));
    }

    /**
     * 获取当日开始时间
     * 使用指定格式解析及输出日期字符串
     *
     * @param dateTimeStr 日期字符串
     * @param pattern     日期格式
     * @return
     * @throws ParseException
     */
    public static String dayStart(@NotBlank String dateTimeStr, @NotBlank String pattern) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        return format.format(dayStart(format.parse(dateTimeStr)));
    }

    /**
     * 获取今日开始时间并按默认日期时间格式{@link #FORMAT_DATE_TIME}输出
     *
     * @return
     */
    public static String todayStart() {
        return SDF_DATE_TIME.format(dayStart(new Date()));
    }

    /**
     * 获取今日开始时间并按指定日期格式输出
     *
     * @param pattern 日期格式
     * @return
     */
    public static String todayStart(@NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(dayStart(new Date()));
    }

    private static void dayStart(Calendar calendar) {
        calendar.set(Calendar.MILLISECOND, 0);
        setTime(calendar, 0, 0, 0);
    }

    /**
     * 获取当日结束时间
     *
     * @return
     */
    public EasyTime dayEnd() {
        dayEnd(instance);
        return this;
    }

    /**
     * 获取当日结束时间
     *
     * @param date 日期
     * @return
     */
    public static Date dayEnd(@NotNull Date date) {
        Calendar calendar = new Calendar.Builder().setInstant(date).build();
        dayEnd(calendar);
        return calendar.getTime();
    }

    /**
     * 获取当日结束时间
     * 解析日期及输出均使用默认日期时间格式{@link #FORMAT_DATE_TIME}
     *
     * @param dateTimeStr 日期字符串
     * @return
     * @throws ParseException
     */
    public static String dayEnd(@NotBlank String dateTimeStr) throws ParseException {
        return SDF_DATE_TIME.format(dayEnd(SDF_DATE_TIME.parse(dateTimeStr)));
    }

    /**
     * 获取当日结束时间
     * 使用指定日期格式解析日期及输出
     *
     * @param dateTimeStr 日期字符串
     * @param pattern     日期格式
     * @return
     * @throws ParseException
     */
    public static String dayEnd(@NotBlank String dateTimeStr, @NotBlank String pattern) throws ParseException {
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        return format.format(dayEnd(format.parse(dateTimeStr)));
    }

    /**
     * 获取今日结束时间并按默认日期时间格式{@link #FORMAT_DATE_TIME}输出
     *
     * @return
     */
    public static String todayEnd() {
        return SDF_DATE_TIME.format(dayEnd(new Date()));
    }

    /**
     * 获取今日结束时间并按指定格式输出
     *
     * @param pattern 日期格式
     * @return
     */
    public static String todayEnd(@NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(dayEnd(new Date()));
    }

    private static void dayEnd(Calendar calendar) {
        calendar.set(Calendar.MILLISECOND, 999);
        setTime(calendar, 23, 59, 59);
    }

    /**
     * 格式化输出
     * 日期格式化输出、日期格式校验
     */

    /**
     * 输出字符串
     * 默认格式为{@link #FORMAT_DATE_TIME}
     *
     * @return
     */
    public String format() {
        return SDF_DATE_TIME.format(instance.getTime());
    }

    /**
     * 根据指定格式输出字符串
     *
     * @param pattern 日期时间格式
     * @return
     */
    public String format(@NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(instance.getTime());
    }

    /**
     * 使用默认格式{@link #FORMAT_DATE_TIME}输出
     *
     * @param date 日期对象
     * @return
     */
    public static String format(@NotNull Date date) {
        return SDF_DATE_TIME.format(date);
    }

    /**
     * 使用默认格式{@link #FORMAT_DATE_TIME}输出
     *
     * @param milliseconds 毫秒数
     * @return
     */
    public static String format(long milliseconds) {
        return SDF_DATE_TIME.format(new Date(milliseconds));
    }

    /**
     * 使用默认日期格式{@link #FORMAT_DATE}输出日期
     *
     * @return
     */
    public String formatDate() {
        return SDF_DATE.format(instance.getTime());
    }

    /**
     * 使用默认日期格式{@link #FORMAT_DATE}输出日期
     *
     * @param date 日期对象
     * @return
     */
    public static String formatDate(@NotNull Date date) {
        return SDF_DATE.format(date);
    }

    /**
     * 使用默认日期格式{@link #FORMAT_DATE}输出日期
     *
     * @param milliseconds 毫秒数
     * @return
     */
    public static String formatDate(long milliseconds) {
        return SDF_DATE.format(new Date(milliseconds));
    }

    /**
     * 使用默认时间格式{@link #FORMAT_TIME}输出时间
     *
     * @return
     */
    public String formatTime() {
        return SDF_TIME.format(instance.getTime());
    }


    /**
     * 使用默认时间格式{@link #FORMAT_TIME}输出时间
     *
     * @param date 日期对象
     * @return
     */
    public static String formatTime(@NotNull Date date) {
        return SDF_TIME.format(date);
    }

    /**
     * 使用默认时间格式{@link #FORMAT_TIME}输出时间
     *
     * @param milliseconds 毫秒数
     * @return
     */
    public static String formatTime(long milliseconds) {
        return SDF_TIME.format(new Date(milliseconds));
    }

    /**
     * 使用给定的日期和格式输出
     *
     * @param date    日期对象
     * @param pattern 格式
     * @return
     */
    public static String format(@NotNull Date date, @NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(date);
    }

    /**
     * 使用给定的日期和格式输出
     *
     * @param milliseconds 毫秒数
     * @param pattern      格式
     * @return
     */
    public static String format(long milliseconds, @NotBlank String pattern) {
        return new SimpleDateFormat(pattern).format(new Date(milliseconds));
    }

    /**
     * 日期时间格式校验
     *
     * @param date    日期时间字符串
     * @param pattern 格式
     * @return 若日期及格式不为空，且按格式解析日期成功，则返回true，否则返回false
     */
    public static boolean valid(@NotBlank String date, @NotBlank String pattern) {
        if (date == null || pattern == null || date.trim().equals("") || pattern.trim().equals("")) {
            return false;
        }
        SimpleDateFormat format = new SimpleDateFormat(pattern);
        format.setLenient(false);
        try {
            format.parse(date);
        } catch (ParseException e) {
            return false;
        }
        return true;
    }


    /**
     * 计算两个日期的天数间隔
     *
     * @param another 另一个{@link EasyTime}对象
     * @return 若当前日期在给出的日期之前，则返回小于0，若晚于给出的日期，则大于0，若是同一天则等于0
     */
    public int countDays(@NotNull EasyTime another) {
        return getEpoDays(
                this.instance.get(Calendar.YEAR),
                this.instance.get(Calendar.MONTH),
                this.instance.get(Calendar.DAY_OF_MONTH)
        ) - getEpoDays(
                another.instance.get(Calendar.YEAR),
                another.instance.get(Calendar.MONTH),
                another.instance.get(Calendar.DAY_OF_MONTH)
        );
    }

    /**
     * 计算两个日期的天数间隔
     *
     * @param start 开始日期
     * @param end   结束日期
     * @return 若当前日期在给出的日期之前，则返回小于0，若晚于给出的日期，则大于0，若是同一天则等于0
     */
    public static int countDays(@NotNull Date start, @NotNull Date end) {
        return init(start).countDays(init(end));
    }

    /**
     * 计算两个日期的天数间隔。使用默认的日期格式{@link #FORMAT_DATE}解析日期。
     *
     * @param start 开始日期
     * @param end   结束日期
     * @return 若当前日期在给出的日期之前，则返回小于0，若晚于给出的日期，则大于0，若是同一天则等于0
     * @throws ParseException
     */
    public static int countDays(@NotBlank String start, @NotBlank String end) throws ParseException {
        return init(start).countDays(init(end));
    }

    /**
     * 计算两个日期的天数间隔
     *
     * @param start   开始日期
     * @param end     结束日期
     * @param pattern 日期格式
     * @return 若当前日期在给出的日期之前，则返回小于0，若晚于给出的日期，则大于0，若是同一天则等于0
     * @throws ParseException
     */
    public static int countDays(@NotBlank String start, @NotBlank String end, @NotBlank String pattern) throws ParseException {
        return init(start, pattern).countDays(init(end, pattern));
    }

    /**
     * 获取标准天
     * 标准天：自公元1年1月1日起的第多少天
     *
     * @param year  年
     * @param month 月
     * @param day   日
     * @return 标准天
     */
    private int getEpoDays(int year, int month, int day) {
        // 正常天数减去闰年天数：逢4、400加1天
        int total = (year - 1) * 365;
        total += ((year - 1) / 4);
        total -= (year - 1) / 100;
        total += (year - 1) / 400;
        for (int i = 0; i < COMMON_MONTH_DAY.length; i++) {
            if (i < month) {
                total += COMMON_MONTH_DAY[i];
            } else {
                break;
            }
        }
        total += day;
        if (month > Calendar.FEBRUARY && isBigYear(year)) {
            total++;
        }
        return total;
    }

    /**
     * 判断是平年还是闰年
     *
     * @param year 年
     * @return 若是闰年则返回true，否则返回false
     */
    private boolean isBigYear(int year) {
        if (year % 4 == 0 && year % 100 != 0) {
            return true;
        }
        if (year % 400 == 0) {
            return true;
        }
        return false;
    }
}
